package com.cmcc.shared.network

import com.cmcc.shared.network.interceptor.HeaderInterceptor
import com.cmcc.shared.network.interceptor.HttpLoggingInterceptor
import com.cmcc.shared.utils.L
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import retrofit2.CallAdapter
import retrofit2.Converter
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit

class RetrofitRequest private constructor(builder: Builder) {

    private var connectTimeout: Int
    private var readTimeout: Int
    private var writeTimeout: Int
    private var baseUrl: String
    private val interceptors: MutableList<Interceptor> = arrayListOf()
    private val converterFactories: MutableList<Converter.Factory> = arrayListOf()
    private val callAdapterFactories: MutableList<CallAdapter.Factory> = arrayListOf()

    private lateinit var okHttpBuilder: OkHttpClient.Builder

    init {
        this.connectTimeout = builder.connectTimeout
        this.readTimeout = builder.readTimeout
        this.writeTimeout = builder.writeTimeout
        this.interceptors.addAll(builder.interceptors)
        this.converterFactories.addAll(builder.converterFactories)
        this.callAdapterFactories.addAll(builder.callAdapterFactories)
        this.baseUrl = builder.baseUrl
    }


    private fun okHttpClient(): OkHttpClient {
        okHttpBuilder = OkHttpClient.Builder()
            .connectTimeout(connectTimeout.toLong(), TimeUnit.SECONDS)
            .readTimeout(readTimeout.toLong(), TimeUnit.SECONDS)
            .writeTimeout(writeTimeout.toLong(), TimeUnit.SECONDS)
            .retryOnConnectionFailure(true)
        try {
            okHttpBuilder.sslSocketFactory(
                SSLSocketFactoryExtended(),
                X509ExtendedTrustManagerImpl()
            )
        } catch (e: Exception) {
            L.d("SSLSocketFactoryExtended:Exception")
        }
        if (interceptors.isNotEmpty()) {
            for (inter in interceptors) {
                okHttpBuilder.addInterceptor(inter)
            }
        }
        return okHttpBuilder.build()
    }

    private fun retrofit(): Retrofit {
        if (baseUrl.isEmpty()) {
            throw RuntimeException("plz call baseUrl(url : String) before build()!")
        }
        val retrofit = Retrofit.Builder()
            .client(okHttpClient())
            .baseUrl(baseUrl)
        for (convert in converterFactories) {
            retrofit.addConverterFactory(convert)
        }

        for (callAdapter in callAdapterFactories) {
            retrofit.addCallAdapterFactory(callAdapter)
        }
        return retrofit.build()
    }

    fun <T> createService(clazz: Class<T>): T {
        return retrofit().create(clazz)
    }

    companion object {
        /**
         * Default
         */
        private const val CONNECT_TIMEOUT_SECOND = 60
        private const val READ_TIMEOUT_SECOND = 60
        private const val WRITE_TIMEOUT_SECOND = 60
    }

    class Builder {


        val converterFactories: MutableList<Converter.Factory> = arrayListOf()
        val interceptors: MutableList<Interceptor> = arrayListOf()
        val callAdapterFactories: MutableList<CallAdapter.Factory> = arrayListOf()
        var baseUrl: String = ""
        var connectTimeout = CONNECT_TIMEOUT_SECOND
        var readTimeout = READ_TIMEOUT_SECOND
        var writeTimeout = WRITE_TIMEOUT_SECOND

        private val networkInterceptor: HeaderInterceptor = HeaderInterceptor()
        private val httpLoggingInterceptor: HttpLoggingInterceptor = HttpLoggingInterceptor()
        private var gsonConverterFactory: Converter.Factory = GsonConverterFactory.create()

        init {
            converterFactories.add(gsonConverterFactory)
            interceptors.add(networkInterceptor)
            interceptors.add(httpLoggingInterceptor)
            httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.URL)
        }

        fun baseUrl(url: String): Builder {
            baseUrl = url
            return this
        }

        fun addIntercptor(interceptor: Interceptor): Builder {
            interceptors.add(interceptor)
            return this
        }

        fun clearIntercptor(): Builder {
            interceptors.clear()
            return this
        }

        fun addConverterFactory(converter: Converter.Factory): Builder {
            converterFactories.add(0, converter)
            return this
        }

        fun defaultConverterFactory(): Builder {
            converterFactories.clear()
            return this
        }

        fun setLogLevel(level: HttpLoggingInterceptor.Level): Builder {
            httpLoggingInterceptor.setLevel(level)
            return this
        }

        fun addCallAdapterFactory(callAdapter: CallAdapter.Factory): Builder {
            callAdapterFactories.add(callAdapter)
            return this
        }

        fun defaultCallAdapterFactory(): Builder {
            callAdapterFactories.clear()
            return this
        }

        fun addHeader(key: String, value: String): Builder {
            networkInterceptor.addHeader(key, value)
            return this
        }

        fun connectTimeout(time: Int): Builder {
            connectTimeout = time
            return this
        }

        fun readTimeout(time: Int): Builder {
            readTimeout = time
            return this
        }

        fun writeTimeout(time: Int): Builder {
            writeTimeout = time
            return this
        }

        fun build(): RetrofitRequest {
            return RetrofitRequest(this)
        }
    }
}